package com.gitee.wsl.doc.prosemirror.ui.keymap

import androidx.compose.ui.input.key.KeyEvent
import androidx.compose.ui.input.key.isAltPressed
import androidx.compose.ui.input.key.isCtrlPressed
import androidx.compose.ui.input.key.isMetaPressed
import androidx.compose.ui.input.key.isShiftPressed
import androidx.compose.ui.input.key.key
import com.gitee.wsl.doc.prosemirror.state.Command
import com.gitee.wsl.doc.prosemirror.ui.EditorView

fun modifiers(name: String, event: KeyEvent, shift:Boolean = true):String {
    var name = name
    if (event.isAltPressed) name = "Alt-$name"
    if (event.isCtrlPressed) name = "Ctrl-$name"
    if (event.isMetaPressed) name = "Meta-$name"
    if (shift && event.isShiftPressed) name = "Shift-$name"
    return name
}

fun keyName(event: KeyEvent):String = Char(event.key.keyCode.toInt()).toString()

typealias KeydownHandler = (view: EditorView, event: KeyEvent) -> Boolean

/// Given a set of bindings (using the same format as
/// [`keymap`](#keymap.keymap)), return a [keydown
/// handler](#view.EditorProps.handleKeyDown) that handles them.
fun keydownHandler(bindings: Map<String, Command>):KeydownHandler {
    //let map = normalize(bindings)
    val map = bindings
    val hander:KeydownHandler = Hander@{view, event->
        val name = keyName(event)
        var baseName:String = ""
        val direct = map[modifiers(name, event)]
        if (direct!=null && direct(view.state, view::dispatch)) return@Hander true
        // A character key
        if (name.length == 1 && name != " ") {
            if (event.isShiftPressed) {
                // In case the name was already modified by shift, try looking
                // it up without its shift modifier
                val noShift = map[modifiers(name, event, false)]
                if (noShift!=null && noShift(view.state, view::dispatch)) return@Hander true
            }
            if ((event.isAltPressed || event.isMetaPressed || event.isCtrlPressed) &&
                // Ctrl-Alt may be used for AltGr on Windows
                !(/*windows &&*/ event.isCtrlPressed && event.isAltPressed) /*&&
                 (baseName = base[event.keyCode]) && baseName != name*/) {
                // Try falling back to the keyCode when there's a modifier
                // active or the character produced isn't ASCII, and our table
                // produces a different name from the the keyCode. See #668,
                // #1060, #1529.
                val fromCode = map[modifiers(baseName, event)]
                if (fromCode!=null && fromCode(view.state, view::dispatch)) return@Hander true
            }
        }
        false
    }
    return hander
}
